
import sys, re
from tori.akatsak import akatsa
import tori.patroiak
import tori.instructions


class parser():
    def __init__(self):
        self.GUI=False
        self.mihiz_funtzioak = {'bin':self.bin,'tbin':self.tbin}

        self.bss = 0        #ez hasieratutako aldagaiak
        self.data = []      #hasieratutako aldagaiak
        self.rodata = []    #irakurketarako datuak
        self.text = []      #instrukzioak

        self.syms = {}      
        self.dsyms = {}     
        self.bsyms = {}     

        self.title = None
        self.space = None
        self.proc  = None

    def parse(self, f,gui=False):
        """Metodo nagusia, lerroka interpretatzen du.
        """
        self.__init__()
        self.GUI=gui
        iruzkina = False
        testua=""
        #iruzkinak kendu
        ln=0
        for lerro in f:
            if self.space=="end":
                continue
            for letra in lerro:
                if not iruzkina and letra!='{':
                    testua+=letra
                elif not iruzkina and letra=='{':
                    iruzkina=True
                elif iruzkina and letra=='}':
                    iruzkina=False
            testua=testua.strip()
            if testua and not testua.isspace():
                self.interpretatu(testua,ln)
                testua=""
            ln+=1


    def interpretatu(self, l,ln):
        """
        """
        if l.isspace():
            return
        # Beharrezkoa da izenburu bat ezartzea
        elif self.space==None:
            e = tori.patroiak.konparatu([tori.patroiak.title],l)
            if not e:
                akatsa(self.GUI, "patroia", katea=l, lerroa=ln)
            else:
                self.title=e.group(1)
                self.space = "data"


        # aldagai globalak ezagutarazi. Hiru aldagai mota daude: .value, .word, eta .proc
        elif self.space=="data":
            e = tori.patroiak.konparatu([tori.patroiak.word,tori.patroiak.value,\
                                        tori.patroiak.proc,tori.patroiak.end],l)
            if not e:
                akatsa(self.GUI, "patroia", katea=l, lerroa=ln)
            else:
                m = e.group(1).lower()
                if m==".proc":
                    self.syms[e.group(2).lower()] = len(self.text)
                    self.proc=e.group(2).lower()
                    self.space="proc"
                elif m==".end":
                    self.space="end"
                else:
                    self.aldagai_globala(e.group(1),e.group(2),e.group(3))

        elif self.space=="proc":
            e = tori.patroiak.konparatu([tori.patroiak.endp,],l)
            if e:
                if e.group(2).lower()!=self.proc:
                    akatsa(self.GUI, "prozedura", p=self.proc)
                else:
                    self.space="data"
                    self.proc=None
            else:
                self.interpretatu_agindua(l,ln)


    #=============================

    def interpretatu_agindua(self,l, ln):
        e = tori.patroiak.konparatu(tori.patroiak.aginduak,l)
        if not e:
            akatsa(self.GUI, "patroia", katea=l, lerroa=ln)
        else:
            g = list(e.groups())
            if g[0]:
                self.syms[g[0].lower().split(':')[0].strip()]=len(self.text)
            g = g[1:]
            for i in range(len(g)):
                if re.match(tori.patroiak.erregistroa,g[i],re.I):
                    if g[i].lower()=='sp':
                        g[i]='31'
                    else:
                        g[i]=g[i][1:]
            if g[0].lower()=='outs':
                g=[g[0],self.dataratu_katea(g[1])]
            self.text.append(tuple(g))


    def aldagai_globala(self, sim, mota, x):
        if mota=='word':
            self.bsyms[sim.lower()] = self.bss
            self.bss+=int(x)
        else:
            self.dsyms[sim.lower()] = len(self.data)
            x = x.split(",")
            for i in x:
                e = tori.patroiak.konparatu([tori.patroiak.balioa],i)
                v=int(e.group(1))
                if e.group(2)==None:
                    n=1
                else:
                    n=int(e.group(2)[1:-1]) # Parentesiak kentzeko
                for j in range(0,n):
                    self.data.append(v)

    def dataratu_katea(self,s):
        """Kate bat emanda kate hori 2 byteko multzotan datutan sartzen du eta
        lehenengo karaktererako erakuslea itzultzen du.
        """
        p = len(self.rodata)
        if not len(s)%2:
            for i in range(0,len(s)-2,2):
                self.rodata.append(ord(s[i])*256+ord(s[i+1]))
            self.rodata.append(0)
        else:
            for i in range(0,len(s)-1,2):
                self.rodata.append(ord(s[i])*256+ord(s[i+1]))
            self.rodata.append(ord(s[-1])*256)
        return p

    def berehalakoa(self,x):
        "Dena dela osoko bihurtzen du"
        #hamaseitarra
        if x[0].lower()=='x':
            return int(x[1:],16)
        #Bitarra
        elif x[0].lower()=='b':
            bitarra = x[-16:]
            if bitarra[0]=='0':
                return int(bitarra[1:],2)
            else:
                a=0
                i=len(bitarra)-1
                while i>=0:
                    a+=int(bitarra[i])*2**(len(bitarra)-1-i)
                    i-=1
                return a-2**len(bitarra)
        #Hamartarra
        else:
            if x[0].isalpha():
                x=x[1:]
            return int(x)

    def txukundu(self,x,ln):
        agindua = x[0].lower()
        kod = [tori.instructions.keys.index(agindua), ]
        kod.extend(x[1:])
        if tori.instructions.ordena_berezia(tori.instructions.agindua(agindua)):
            kod = [kod[0],kod[1],kod[3],kod[2]]
        if tori.instructions.berehalakoa(tori.instructions.agindua(agindua)):
            kod[-1] = self.berehalakoa(kod[-1])
        elif tori.instructions.erlatiboa(tori.instructions.agindua(agindua)):
            kod[-1]=kod[-1] and int(kod[-1]) or 0
        elif tori.instructions.etiketaduna(tori.instructions.agindua(agindua)):
            if not self.syms.has_key(kod[-1].lower()):
                akatsa(self.GUI, "etiketa", etiketa=kod[-1])
            else:
                kod[-1]=(self.syms[kod[-1].lower()]-ln)*2
        elif tori.instructions.helbidea(tori.instructions.agindua(agindua)):
            if kod[-1].isdigit():
                kod[-1]=int(kod[-1])
            else:
                if not (self.dsyms.has_key(kod[-1].lower()) or self.bsyms.has_key(kod[-1].lower())):
                    akatsa(self.GUI, "etiketa", etiketa=kod[-1])
                elif self.dsyms.has_key(kod[-1].lower()):
                    kod[-1] = self.dsyms[kod[-1].lower()]+len(self.rodata)
                else:
                    kod[-1] = self.bsyms[kod[-1].lower()]+len(self.rodata)+len(self.data)
        else:
            kod[-1]= kod[-1] and int(kod[-1]) or 0
        return kod

    #===============================================

    def bin(self, out=sys.stdout):
        import bin
        return bin.plain_bin(self, out, gui=self.GUI)
        

    def tbin(self, out=sys.stdout):
        import bin
        return bin.text_bin(self, out, gui=self.GUI)

    def elf(self, out=sys.stdout):
        pass

    def lis(self, out=sys.stdout):
        pass

    


